﻿using CPPEI.Extensions;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Xml;

namespace CPPEI.WebApi.Packaging
{
    public static class ModuleDefDocument
    {
        public static ModuleDef Load(string filePath)
        {
            using(FileStream stream = new FileStream(filePath, FileMode.Open))
            {
                return Load(stream);
            }
        }

        public static ModuleDef Load(Stream stream)
        {
            XmlDocument xDoc = CPPEI.Extensions.XmlDocExtension.GetDocument(stream);
            if (xDoc == null)
            {
                return null;
            }

            XmlNode xModule = xDoc.GetNode("Module");

            XmlNode xAssembly = xModule.GetNode("Assembly");
            XmlNode xName = xModule.GetNode("Name");
            XmlNode xType = xModule.GetNode("Type");
            XmlNode xFile = xModule.GetNode("File");

            ModuleDef module = new ModuleDef();
            module.Name = xName.GetValue();
            module.Assembly = xAssembly.GetValue();
            module.Type = xType.GetValue();
            module.File = xFile.GetValue();

            if (string.IsNullOrEmpty(module.Name))
            {
                return null;
            }

            XmlNode xReferences = xModule.GetNode("References");
            XmlNodeList xReferenceItems = xReferences.GetNodes("Reference");
            if (xReferenceItems != null)
            {
                foreach (XmlNode xReferenceItem in xReferenceItems)
                {
                    RefDef refDef = LoadRef(xReferenceItem);
                    if (refDef != null)
                    {
                        module.Refs.Add(refDef);
                    }
                    else
                    {
                        // 出现错误
                        return null;
                    }
                }
            }

            XmlNode xActions = xModule.GetNode("Actions");
            XmlNodeList xActionItems = xActions.GetNodes("Action");
            if (xActionItems != null)
            {
                foreach (XmlNode xActionItem in xActionItems)
                {
                    ActionDef actionDef = LoadAction(xActionItem);
                    if (actionDef != null)
                    {
                        module.Actions.Add(actionDef);
                    }
                    else
                    {
                        // 出现错误
                        return null;
                    }
                }
            }
            return module;
        }

        private static RefDef LoadRef(XmlNode xReference)
        {
            string assembly = xReference.GetAttributeValue("Assembly");
            string file = xReference.GetAttributeValue("File");
            if (!string.IsNullOrEmpty(assembly) && !string.IsNullOrEmpty(file))
            {
                RefDef refDef = new RefDef();
                refDef.Assembly = assembly;
                refDef.File = file;
                return refDef;
            }
            return null;
        }

        private static ActionDef LoadAction(XmlNode xAction)
        {
            string type = xAction.GetAttributeValue("Type");
            string name = xAction.GetAttributeValue("Name");
            string scenario = xAction.GetAttributeValue("Scenario");
            if (!string.IsNullOrEmpty(type) && !string.IsNullOrEmpty(name) && !string.IsNullOrEmpty(scenario))
            {
                ActionDef actionDef = new ActionDef();
                actionDef.Type = type;
                actionDef.Name = name;
                actionDef.Scenario = scenario;
                return actionDef;
            }
            return null;
        }

        public static bool Save(ModuleDef module, string filePath)
        {
            XmlDocument xDoc = new XmlDocument();
            XmlDeclaration xDeclaration =  xDoc.CreateXmlDeclaration("1.0", "utf-8", "yes");
            xDoc.AppendChild(xDeclaration);

            XmlNode xModule = xDoc.SetNode("Module");

            XmlNode xAssembly = xModule.SetNode("Assembly");
            XmlNode xName = xModule.SetNode("Name");
            XmlNode xType = xModule.SetNode("Type");
            XmlNode xFile = xModule.SetNode("File");

            xName.SetValue(module.Name);
            xAssembly.SetValue(module.Assembly);
            xType.SetValue(module.Type);
            xFile.SetValue(module.File);

            XmlNode xReferences = xModule.SetNode("References");
            foreach (RefDef refDef in module.Refs)
            {
                XmlNode xReferenceItem = xReferences.SetNode("Reference");
                xReferenceItem.SetAttribute("Assembly", refDef.Assembly);
                xReferenceItem.SetAttribute("File", refDef.File);
            }

            XmlNode xActions = xModule.SetNode("Actions");
            foreach (ActionDef actionDef in module.Actions)
            {
                XmlNode xActionItem = xActions.AppendNode("Action");
                xActionItem.SetAttribute("Scenario", actionDef.Scenario);
                xActionItem.SetAttribute("Name", actionDef.Name);
                xActionItem.SetAttribute("Type", actionDef.Type);
            }

            try
            {
                xDoc.Save(filePath);
                return true;
            }
            catch(Exception ex)
            {
                return false;
            }
        }
    }
}
